/*
* @Author: z.p
* @Project: Zdotp
* @Date: 2025年01月14日
* @Description: actor对象池管理器
*/

using System.Reflection;
using Zdotp.Logs;

namespace Zdotp.ObjectPool;

public static class ObjectPoolManager
{
    public static bool IsLogger = false;
    private static readonly Dictionary<Type, ObjectPoolBase> _pools = new();
    private static readonly ZLogger _logger = LogHelper.CreateLogger($"objectPool-manager");

    public static void LoadAssemblies(List<Assembly> assemblies)
    {
        var poolTypes = new List<IPoolConfig.PoolType>();
        foreach (var assembly in assemblies)
        {
            foreach (var classType in assembly.GetTypes())
            {
                var baseType = classType.BaseType;
                if (baseType == null) continue;
                var isPObject = false;
                while (baseType != null)
                {
                    if (baseType == typeof(ObjectBase))
                    {
                        isPObject = true;
                        break;
                    }
                    baseType = baseType.BaseType;
                }

                if (isPObject)
                {
                    poolTypes.Add(new IPoolConfig.PoolType(classType, classType.Name));
                }
            }
        }
        // 创建对象池实例
        foreach (var poolType in poolTypes)
        {
            var type = poolType.Type;
            var objectPoolType = typeof(ObjectPool<>);
            var constructedType = objectPoolType.MakeGenericType(type);
            var objectPoolInstance = Activator.CreateInstance(constructedType);
            if (objectPoolInstance is ObjectPoolBase pool)
            {
                _pools.Add(type, pool.Build(poolType));
            }
        }
    }
    
    private static ObjectPool<T>? GetPool<T>() where T : ObjectBase, new()
    {
        ObjectPoolBase? requirePool = null;
        if (_pools.ContainsKey(typeof(T)))
        {
            requirePool = _pools[typeof(T)];
        }
        if (requirePool is not ObjectPool<T> pool)
        {
            _logger.Error($"objectPool not found, type : {typeof(T).Name}");
            return null;
        }
        return pool;
    }

    public static T? GetObj<T>(Action<T>? init = null, Action<T>? callback = null) where T : ObjectBase, new()
    {
        var pool = GetPool<T>();
        if (pool is null)
        {
            return null;
        }
        var data = pool.GetObj(init, callback);
        if (data != null)
        {
            return data;
        }
        _logger.Error($"objectPool get null object, type : {typeof(T).Name}");
        return null;
    }
    public static void ReleaseObj<T>(T obj) where T : ObjectBase, new()
    {
        var pool = GetPool<T>();
        pool?.ReleaseObj(obj);
    }
    
    public static void ReleaseObj(Type objectType, ObjectBase obj)
    {
        ObjectPoolBase? requirePool = null;
        foreach (var ePool in _pools)
        {
            var value = ePool.Value;
            if (value.PoolType.Type == objectType)
            {
                requirePool = value;
                break;
            }
        }
        if (requirePool is null)
        {
            _logger.Error($"objectPool not found, type : {objectType.Name}");
            return;
        }
        requirePool.ReleaseObj(obj);
    }
}